#!/usr/bin/perl -w
#Modulo ListarUI del TP-Grupo 9 Sistemas Operativos - FIUBA
#
#Autor: Pablo M. Angelani 92.707
#
# Este modulo contiene toda las subrutinas de USER-INTERFACE (UI) del ListarV5.
#

use constant TRUE => 1;
use constant FALSE => 0;

$RM_IFS = ",";
$MAESIST = "$ENV{'MAEDIR'}/sistemas";
$MAEPAT = "$ENV{'MAEDIR'}/patrones";

sub escribirArchivo{
	my $salida = shift(@_); my $mje = shift(@_);
	if ($salida){
		open(OUT, ">>$salida"); 
		print OUT $mje;
		close(OUT);
	}
}

sub mostrarSeparador{
	my $salida = shift(@_);
	for (my $i = 0; $i < (split(/ /,`/bin/stty size`))[1]/4; $i+=1){ print "----"; escribirArchivo($salida, "----");};
	for (my $i = 0; $i < (split(/ /,`/bin/stty size`))[1]%4; $i+=1){ print "-"; escribirArchivo($salida, "-");};
	print "\n";
	escribirArchivo($salida, "\n");
}


#
# Muesta el siguiente help del script:
#-----------------------------------------------------------------
#ListarV5: El propósito de este programa perl es resolver 
#consultas efectuadas sobre los archivos de resultados globales 
#y resultados detallados.
#
#Opciones:
#	-g
#		La consulta resolverá consultas sobre cantidad de hallazgos
#		(RGLOBALES.PAT_ID)
#	-r
#		La consulta listará resultados extraídos de los archivos
#		RESULTADOS.PAT_ID
#	-h
#		Muestra la ayuda.
#	-x
#		Esta opción además de emitir por pantalla, grabar el informe 
#		en el directorio REPODIR
#
sub verAyuda
{
	mostrarSeparador();
	print "Uso: ListarV5 [opciones]\n\n";
	print "ListarV5: El propósito de este programa perl es resolver consultas efectuadas sobre los archivos de resultados globales y resultados detallados.\n";
	print "Opciones:\n";
	print "\t-g\n\t\tPerminte cambiar la extension default de _LOGFILE.\n";
	print "\t-r\n\t\tLa consulta listará resultados extraídos de los archivos RESULTADOS.PAT_ID.\n";
	print "\t-h\n\t\tMuestra la ayuda.\n";
	print "\t-x\n\t\tEsta opción además de emitir por pantalla, grabar el informe en el directorio REPODIR.\n";
	mostrarSeparador();
	exit 0;
}


#
# Guia al usuario en el ingreso de filtros para obtener el listado deseado.
#
# Params:
#		@_[0]:
#			Referencia al filtro seleccionado por el usuario.
#			Valores Posibles: PATRON, ARCHIVO, CICLO
#
sub menuOpcionR{
	# Referencia al filtro y su argumento	
	my $filtro = shift (@_); my $argumento = shift (@_);
	my $modo_busqueda = ""; my $arg_busqueda = "";
	
	mostrarSeparador();
	print "Buscando resultados detallados de los archivos de patrones.\nIngrese 'q' para cancelar la busqueda.\n\n";
	${$filtro} = "";
	do{
		print "Ingrese como desea realizar la busqueda: patron(p: <id_patron>), ciclo de busqueda(c: <numero_ciclo>) o archivo(a: <nombre_archivo>).Solo puede ingresar un filtro para la consulta.\nEjemplo de entrada valida: p: 112).\n";
		$entrada = <STDIN>;
		chomp($entrada);
		#Parseo la entrada del usuario.

		if ($entrada =~ m/^p\:\s\d+$/){
			${$filtro} = PATRON;
		} elsif ($entrada =~ m/^c\:\s\d+$/){
			${$filtro} = CICLO;
		} elsif ($entrada =~ m/^a\:\s[\w\_\-\d\.]+$/){
			${$filtro} = ARCHIVO;
		} elsif ($entrada =~ m/^q/){
			exit 0;
		} elsif ($entrada =~ m/^[p c]\:\s\w+$/){
			print "\nEl argumento ingresado no corresponde con el tipo esperado.\n";
			mostrarSeparador();
		} else { 
			print "\nLa opcion ingresada no es valida.\n";
			mostrarSeparador();
		};

	}while(!${$filtro});
	$entrada =~ s/[p c a]\:\s//g;	
	${$argumento} = $entrada;
	mostrarSeparador();
}

#
# Notifica al usuario que no se encontraron resultados para su
# pedido.
#
sub notificacionBusquedaVacia{
	print "\nLos sentimos, pero su solicitud de busqueda no presenta resultados por el momento.\n";
}


#
# Guia al usuario en la seleccion de los posibles resultados buscados.
# Param:
#		$_[0]:
#			Filtro de la consulta. Valores posibles: PATRON, 
#												CICLO, ARCHIVO.
#		$_[1]:
#			Referencia al hash de resultados a listar.
#		$_[2]:
#			Referencia al array de selecciones del usuario.
#Return:
#		Esta subrutina devuelvo el array S_[2] completo con los
#		elementos seleccionados por el usuario.
#
sub menuSeleccionResultados{
	my $filtro = shift @_; my $hash = shift @_; my $opt = shift @_; my $i = 0; my @array=[];
	
	print "$filtro:\n";

	if (!scalar %{$hash}){
		print "Sin resultados. \n";	return;
	}

	foreach my $res (sort keys %{$hash}){
		print "($i)\t$res\n";
		push (@array, $res);
		$i += 1;
	}
	print "\nSeleccione el numero de los resultados que quiere ver detallados separados por ',' (ej: 0,4,5) o <enter> si no le interesa ninguno: ";
	
	do{
		$opt_valida = TRUE;
		@{$opt} = split(/[, \n]/, <STDIN>);
		foreach my $num (@{$opt}){
			if ($num !~ m/^\d+$/ || $num >= $i){
				print "\nLa secuencia ingresada no es valida, intente nuevamente: ";
				$opt_valida = FALSE;
				last;
			} else {
				$num = $array[$num+1];
			}
		}
	}while(!$opt_valida);
	mostrarSeparador();
}


sub presentacionResultados{
	mostrarSeparador(${_[2]});
	my $mje = "Se ha completado la busqueda! A continuacion se muestran en detalle los resultados solicidatos para:\n\tFiltro: ".$_[0]."\n\tValor: ".$_[1]."\nOrdenados por categorias:\n";
	print $mje;
	escribirArchivo(${_[2]}, $mje);
	mostrarSeparador(${_[2]});
	
}

sub verificarErroresDeUso{
my %opt=%{$_[0]};
#Verifico que no se haya seleccionado -g y -r (son mutuamente
#excluyentes
print "Se ha producido un error, -g y -r son opciones excluyentes, ver help (-h)" if (defined $opt{g} && defined $opt{r});

}


#
# Muestra por pantalla el todos los resultados en detalle de la opcion
# -r.
# Params:
#		$_[0]:
#			Categoria a mostrar por pantalla.
#		$_[1]:
#			Referencia al hash de todos los resultados.
#		S_[2]:
#			Referencia al array de resultados que el usuario selecciono
#
sub mostrarResultados{
	my $fil = shift(@_);my $resultados_ref = shift(@_);my $selec_ref = shift(@_); my $salida = shift(@_);

	if (!scalar @{$selec_ref}){return;};
	print "Por categoria $fil:\n";
	escribirArchivo("$salida", "Por categoria $fil:\n");
	mostrarSeparador($salida);
	foreach my $pat (keys %{$resultados_ref}){
		foreach my $r (@{ ${$resultados_ref}{$pat}}){
			foreach my $sel (@{$selec_ref}){
 				if (($fil eq ARCHIVO && $$r{ARCHIVO} eq $sel) || 
					($fil eq CICLO && $$r{CICLO} eq $sel) || 
					($fil eq PATRON && $$r{PATRON} eq $sel)){
					printf ("Ciclo:\n\t%d\nArchivo:\n\t%s\nNro. de Registro:\n\t%d\nRespuesta:\n\t%s",$$r{CICLO}, $$r{ARCHIVO},$$r{NRO_REGISTRO},$$r{RESPUESTA}."\n");
					escribirArchivo("$salida", "Ciclo:\n\t$$r{CICLO}\nArchivo:\n\t$$r{ARCHIVO}\nNro. de Registro:\n\t$$r{NRO_REGISTRO}\nRespuesta:\n\t$$r{RESPUESTA}\n");
					mostrarSeparador("$salida");
				}
			}

		}
	}
	mostrarSeparador("$salida");
}

#Muestra las opciones acerca de las consultas que se pueden realizar
sub menuOpcionesG
{
		
	mostrarSeparador();
	print "Consultas relacionadas con la totalidad de hallazgos.\n";
	print "Opciones:\n";
	print "\ta:\n\t\tListar el patrón y/o sistema y/o archivo en que se produjo la mayor cantidad de hallazgos.\n";
	print "\tb:\n\t\tListar el patrón y/o sistema y/o archivo en que no se produjo ningún hallazgo.\n";
	print "\tc:\n\t\tMostrar las expresiones regulares que registraron la mayor cantidad de hallazgos.\n";
	print "\td:\n\t\tMostrar las expresiones regulares que registraron la menor cantidad de hallazgos.\n";
	print "\te:\n\t\tListar archivos que presentaron hallazgos en un determinado rango.\n";
	print "\tq:\n\t\tSalir.\n";
	mostrarSeparador();
	
	print "\nIngrese una opción: ";
	$entrada = <STDIN>;
	chomp($entrada);	
	print "\n"; 
	
	#Se repetirá hasta que se ingrese una opción correcta
	while( !($entrada =~ m/[q a b c d e]/i) || (length($entrada) > 1) ){
		print "Entrada inválida. Vuelva a ingresar una opción.\n";
		$entrada = <STDIN>;
		chomp($entrada);		
	}

	return $entrada;
}

#Concatena los distintos patrones/ciclos según corresponda, con el caracter ',' validando que sean entreros
sub validarEnteros{
	my $parametro = shift(@_);
	#Separo los distintos patrones, verifico que sean enteros y los concateno separandolos con ','
	my @args = split(" ", ${$parametro});
	${$parametro} = "";

	foreach $arg (@args){
		chomp($arg);		
		if(!($arg =~ m/\D/i)){
			${$parametro} = ${$parametro}.",".$arg;			
		}		
		else{
			print "No existe el id: $arg.\n";	
		}	
	}
	${$parametro} .= ",";
}

sub cargarSistemas{
	my $sist = shift(@_);
	if(open(FILE,$MAEPAT)){
		$ifs = $RM_IFS;
		while($reg=<FILE>){ 
			my @regs  = split($ifs, $reg);	
			$ID_Sist = $regs[2];$ID_Pat = $regs[0]; 
			if(exists(${$sist}{$ID_Sist})){ 
				${$sist}{$ID_Sist} .= ",".$ID_Pat; 
				#push(@{${$sist}{$ID_Sist}}, $ID_Pat); 
			}
		}
		${$sist}{$ID_Sist} .= "," if(exists(${$sist}{$ID_Sist})); 
		close(FILE);
	}
	else { print "Error al abrir el archivo Maestro patrones.\n"; }	
}

sub validarSistemas{
	my $arg = shift(@_);my $sistemas = shift(@_);
	# Separo los distintos id de sistemas, verifico que existan en el archivo maestro de sistemas 
	if(open(FILE,$MAESIST)){
		$ifs = $RM_IFS;
		while($reg=<FILE>){ 
			my @regs  = split($ifs, $reg);	
			$ID_Sist = $regs[0];
			if($$arg =~ m/$ID_Sist/i){
				#Si el sistema existe, lo borro de la busqueda y lo agrego al resto de los ids
				$$arg =~ s/$ID_Sist//; 
				${$sistemas}{$ID_Sist} = "";
				#Si no se ingreso ningun Id de sistemas, se cargan todos
			} elsif( length $$arg == 0){
				${$sistemas}{$ID_Sist} = ""; 	
			}

		}
		close(FILE);
		#Verifico si quedaron id de sistema no encontrados
		my @rechazados = split (" ",$$arg); 
		foreach $r (@rechazados){
			print "No se encontro el sistema de ID: $r\n";
		}
		cargarSistemas($sistemas);
	}
	else { print "Error al abrir el archivo Maestro sistemas.\n"; }	
}


sub cargarDatos{
	my $arg = shift(@_); my $filtros = shift(@_); my $argumentos = shift(@_);	
	my $entradaValida = 1;

	if(defined(@{$arg})){
		foreach $i (@{$arg}){ chomp($i) if $i;}
		if (! $$arg[0]){ return 0 }
		elsif ($$arg[0] eq "q"){ return 1}
		elsif ($$arg[0] eq "p"){ 
			push(@{$filtros},PATRON);
			#Verifico si hay patrones a consultar
			if(length($$arg[1]) > 0){							
				validarEnteros(\$$arg[1]); 
				${$argumentos}{PATRON} = $$arg[1];		
			}
			else{${$argumentos}{PATRON} = ();}	
		}	
		elsif ($$arg[0] eq "s"){
			push(@{$filtros},SISTEMA);
			${$argumentos}{SISTEMA} = ();
			validarSistemas(\$$arg[1],\%{${$argumentos}{SISTEMA}});
		}
		elsif ($$arg[0] eq "a"){ 
			push(@{$filtros},ARCHIVO);
			#Verifico si hay patrones a consultar
			if(length($$arg[1]) > 0){ 
				my @args = split(" ", $$arg[1]); 
				$$arg[1] = join(",", @args);
				$$arg[1] .= ",";
				${$argumentos}{ARCHIVO} = $$arg[1];		
			}
			else{${$argumentos}{ARCHIVO} = ();}
		}
		else{ $entradaValida = 0;}
	}else{ $entradaValida = 0;}
	
	return $entradaValida;


}

sub determinarFiltrosArgumentos{
	# Referencia a los filtros y sus argumentos	
	my $filtros = shift (@_); my $argumentos = shift (@_);
	my $entradaValida = 0;
	
	mostrarSeparador();
	print "Resolviendo consultas relacionadas con la totalidad de hallazgos.\nIngrese 'q' para cancelar el proceso.\n\n";
	
	do{
	print "Ingrese los parámetros sobre los que se realizará la consulta: patron( :p <id_patron>), sistema(:s <sis_id>) o archivo(:a <nombre_archivo>).\nSe pueden ingresar varios patrones, sistemas o archivos (separando por espacios), si no se especifica alguno, la consulta se realizará sobre todos los patrones, sistemas y archivos existentes de acuerdo a las opciones ingresadas.\nEjemplo de uso: :p 2 33 123 :s 1 4\n";
		$entrada = <STDIN>;
		#Separo los distintos filtros
		my @f_entrada = split(":",$entrada); 
		if(scalar @f_entrada > 0){
			foreach $f (@f_entrada){
				#Separo filtro y argumentos
				if(length $f == 0){ next; }
				my @aux = split(" ", $f); 
				$arg[0] = shift(@aux);
				$arg[0] =~ s/\s// if(defined ($arg[0]));
				$arg[1] = join(" ",@aux);
				$entradaValida = cargarDatos( \@arg, $filtros , $argumentos);
			}
		}
		if(!$entradaValida){
			print "Entrada Invalida. Vuelva a ingresar los datos.\n";
			mostrarSeparador();
		}
	}while (!$entradaValida);
	
	mostrarSeparador();
}

sub determinarCantExpresiones{
		
	mostrarSeparador();
	print "Resolviendo consultas relacionadas con la cantidad de hallazgos registrados en expresiones regulares.\nIngrese 'q' para cancelar el proceso.\n\n";
	
	print "Indique la cantidad de expresiones regulares que desea que respondan a su consulta\n\n";

	my $cantidad =  <STDIN>;
	chomp($cantidad);
	#Verifico que se trate de un numero
	while(($cantidad =~ m/\D/i) && ($cantidad ne "q")){
		print "Entrada inválida. Ingrese un número.\n";
		$cantidad = <STDIN>;
		chomp($cantidad);	
	}
	mostrarSeparador();	
	return $cantidad; 

}

sub determinarArchivosRango{
	
	my $filtros = shift(@_); my $argumentos = shift(@_); my $desde = shift(@_); my $hasta = shift(@_);
	my $entradaValida = 0;	
	mostrarSeparador();
	print "Resolviendo consultas relacionadas con archivos que presentaron hallazgos un determinado rango.\nIngrese 'q' para cancelar el proceso.\n\n";
	
	print "Indique los archivos sobre los que desea resolver la consulta(:a <nombre_archivo>) y el rango de hallazgos que deben presentar(:d <valor_inicial> :h <valor_final>).\n Si no se ingresa un valor de inicio se tomará por defecto el valor inicial 0\n\n";
	
	do{	
		${$desde} = 0;
		${$hasta} = 4000;
		my $entrada = <STDIN>;
		chomp($entrada);
		#Separo los distintos parámetros
		my @f_entrada = split(":",$entrada);
		if(scalar @f_entrada > 0){
			foreach $f (@f_entrada){
				if(length $f == 0){ next; }
				my @aux = split(" ", $f); 
				$arg[0] = shift(@aux);
				$arg[0] =~ s/\s// if(defined ($arg[0]));
				$arg[1] = join(" ",@aux);
				if($arg[0] eq "a"){
					$entradaValida = cargarDatos( \@arg, $filtros , $argumentos);
				}
				if(($arg[0] eq "d") ||($arg[0] eq "h")){
				#Saco los espacios y verfico que se trate de un entero 
					$arg[1] =~ s/\s//g; chomp($arg[1]);					
					if(!($arg[1] =~ m/\D/i)){ 
						${$desde} = $arg[1] if ($arg[0] eq "d");
						${$hasta} = $arg[1] if ($arg[0] eq "h");			
					}		
					else{
						print "Se ingreso un valor inválido, se tomará uno por defecto.\n";	
					}
				}
			}
		}
		if(!$entradaValida){ print "Entrada inválida. Vuelva a ingresar los datos\n"; }
	}while(!$entradaValida);
	mostrarSeparador();
}

sub listarResultadosGlobales{
	my $consulta = shift(@_); my $resultados = shift(@_); my $salida = shift(@_);
		
	mostrarSeparador();
	escribirArchivo($salida, "Resultados de consultas Globales.\n Se realizo la consulta: \n");
	print "Resultados de consultas Globales.\n Se realizo la consulta: \n";
	if($consulta eq "a"){
		escribirArchivo( $salidav, "\ta:\n\t\tListar el patrón y/o sistema y/o archivo en que se produjo la mayor cantidad de hallazgos.\n");
		print "\ta:\n\t\tListar el patrón y/o sistema y/o archivo en que se produjo la mayor cantidad de hallazgos.\n";
	}
	elsif($consulta eq "b"){
		escribirArchivo( $salida , "\tb: Listar el patrón y/o sistema y/o archivo en que no se produjo ningún hallazgo.\n");
		print "\tb: Listar el patrón y/o sistema y/o archivo en que no se produjo ningún hallazgo.\n";
	}
	elsif($consulta eq "c"){
		escribirArchivo( $salida, "\tc: Mostrar las expresiones regulares que registraron la mayor cantidad de hallazgos.\n");
		print "\tc: Mostrar las expresiones regulares que registraron la mayor cantidad de hallazgos.\n";
	}
	elsif($consulta eq "d"){
		escribirArchivo($salida, "\td: Mostrar las expresiones regulares que registraron la menor cantidad de hallazgos.\n" );
		print "\td: Mostrar las expresiones regulares que registraron la menor cantidad de hallazgos.\n";
	}
	elsif($consulta eq "e"){
		escribirArchivo($salida,"\te: Listar archivos que presentaron hallazgos en un determinado rango.\n");
		print "\te: Listar archivos que presentaron hallazgos en un determinado rango.\n";
	}
	escribirArchivo($salida, "\nResultados: \n\n");
	print "\nResultados: \n\n";
	if((scalar( keys %{$resultados})) == 0){
		escribirArchivo($salida, "No se encontraron resultados a su consulta.\n");
		print "No se encontraron resultados a su consulta.\n";	
	}
	foreach my $filtro (keys %{$resultados}){ 
		#Separo los campos del resultado
		if(exists(${$resultados}{$filtro}{NOMBRE}) && exists(${$resultados}{$filtro}{CANTIDAD})){
			
			#Si el primer caracter del string es ',' entonces lo elinimo
			${$resultados}{$filtro}{NOMBRE} =~ s/^,//g if(${$resultados}{$filtro}{NOMBRE} =~ m/^,/i);
			${$resultados}{$filtro}{CANTIDAD} =~ s/^,//g if(${$resultados}{$filtro}{CANTIDAD} =~ m/^,/i);
			
			my @resNombres = split(",",${$resultados}{$filtro}{NOMBRE});
			my @resCantidad = split(",",${$resultados}{$filtro}{CANTIDAD});
			
			if(scalar @resNombres == 0){
				escribirArchivo($salida, "No se encontraron resultados a su consulta.\n");
				print "No se encontraron resultados a su consulta.\n";
			}
			else{ 
				for($i = 0; $i <= $#resNombres; $i++){
					if(length $resNombres[$i]  > 0){
						if( $consulta =~ m/[a b]/i ){ $resCantidad[$i] = $resCantidad[0]; } 
						escribirArchivo($salida, "\tFILTRO: $filtro      RESULTADO: $resNombres[$i]    CANTIDAD HALLAZGOS:$resCantidad[$i] \n");
						print "\tFILTRO: $filtro      RESULTADO: $resNombres[$i]    CANTIDAD HALLAZGOS:$resCantidad[$i] \n";
					}
				}
			}
			escribirArchivo($salida, "\n");
			print "\n";
		}
	}
	
	mostrarSeparador();	
}

1;


